home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / DB_CLIPP / 0769B.ZIP / DBF2MEMO.PAS < prev    next >
Pascal/Delphi Source File  |  1986-05-10  |  23KB  |  883 lines

  1. {$C-}
  2. { Turbo Pascal program to copy dBASE III Char fields TO Memo files   }
  3. { By J. Troutman  74746,1567   5/8/85                                }
  4. { minor revisions 5/3/86 to allow proper access to dBASE III Plus files}
  5. PROGRAM CharToMemo;
  6.  
  7. (* This program will copy designated character fields to a designated
  8.    Memo field.  This was one of my early attempts at a Turbo Pascal
  9.    program, so the code is rather rough at places.  However, it does
  10.    show how to access both .DBF files and .DBT files.
  11.    See DBF.PAS for some (slightly) more polished routines for
  12.    accessing .DBF files.                                             *)
  13.  
  14. CONST
  15.   VER = '1.01';
  16. {Revised to fix incompatibility with dBASE III Plus files }
  17.  
  18. {  Start of Include file: GetStrng.pas}
  19. (* GetStrng is a routine I used to use to validate user input.  There are
  20.    several better routines for doing this in DL 1.  See EDIT.PAS (the one
  21.    with uploaded with PPN [76703,3015] for a good example.               *)
  22. {---------------------------------------------------------------------------}
  23. TYPE
  24.   Str80 = STRING[80];
  25.   ValidChar = SET OF Char;
  26.  
  27.   PROCEDURE PutMessage(Message : Str80);
  28.   VAR
  29.     X, Y, L : Byte;
  30.  
  31.   BEGIN
  32.   X := WhereX;
  33.   Y := WhereY;
  34.   L := Length(Message);
  35.   IF L = 0 THEN
  36.     BEGIN
  37.     GoToXY(1, 25);
  38.     ClrEol;
  39.     END
  40.   ELSE
  41.     BEGIN
  42.     GoToXY(((80-L) DIV 2), 25);
  43.     Write(Message);
  44.     END;
  45.   GoToXY(X, Y);
  46.   END;
  47.  
  48.   FUNCTION GetStrng(Valid : ValidChar;
  49.                     InputLen, Row, Col : Byte;
  50.                     Shift : Boolean) : Str80;
  51.  
  52.   CONST
  53.     ErrorMessage : Str80 = 'Invalid key!  Please try again.';
  54.  
  55.   VAR
  56.     Key : Char;
  57.     Len : Byte;
  58.     Mask,Temp : Str80;
  59.     KeyError : Boolean;
  60.  
  61.   BEGIN
  62.   Temp := '';
  63.   KeyError := False;
  64.   Len := 1;
  65.   FillChar(Mask,SizeOf(Mask),$B0);
  66.   Mask[0] := Chr(InputLen);
  67.   GoToXY(Col, Row);
  68.   Write(Mask);
  69.   GoToXY(Col, Row);
  70.   Read(Kbd, Key);
  71.   WHILE Key <> ^M DO
  72.     BEGIN
  73.     IF Shift THEN Key := UpCase(Key);
  74.     IF (Key IN Valid) AND (Len <= InputLen) THEN
  75.       BEGIN
  76.       Temp := Temp+Key;
  77.       Len := Succ(Len);
  78.       Write(Key);
  79.       IF KeyError THEN
  80.         BEGIN
  81.         PutMessage('');
  82.         KeyError := False;
  83.         END;
  84.       END
  85.     ELSE
  86.       BEGIN
  87.       IF (Key = ^H) AND (Len <> 1) THEN
  88.         BEGIN
  89.         Len := Len-1;
  90.         Write(^H+'_'+^H);
  91.         Delete(Temp, Len, 1);
  92.         IF KeyError THEN
  93.           BEGIN
  94.           PutMessage('');
  95.           KeyError := False;
  96.           END;
  97.         END
  98.       ELSE
  99.         IF Key <> ^M THEN
  100.           BEGIN
  101.           KeyError := True;
  102.           PutMessage(ErrorMessage);
  103.           END;
  104.       END;
  105.     IF (InputLen = 1) AND (Len = 2) THEN
  106.       Key := ^M
  107.     ELSE
  108.       Read(Kbd, Key);
  109.     END;
  110.   GetStrng := Temp;
  111.   IF KeyError THEN PutMessage('');
  112.   END;
  113. {---------------------------------------------------------------------------}
  114. {  End of Include File GetStrng.pas }
  115.  
  116. CONST
  117.   BUFFSIZE = 25599;           { counting from 0 }
  118.   MAX_BYTES_IN_RECORD = 4000; { dBASE III record limit }
  119.   MAX_FIELDS_IN_RECORD = 128; { dBASE III field limit  }
  120.   BYTES_IN_FILE_RECORD = 128; { Turbo BlockRead/Write default record  }
  121.   BYTES_IN_MEMO_RECORD = 512; { dBASE III memo field record size }
  122.  
  123. TYPE
  124.   HeaderType = ARRAY[0..31] OF Byte; { dBASE III header }
  125.   FieldType = ARRAY[0..31] OF Byte; { dBASE III field definitions }
  126.   DBFRecord = ARRAY[0..MAX_BYTES_IN_RECORD] OF Byte;
  127.   Str255 = STRING[255];
  128.   Str10 = STRING[10];
  129.   BufferType = ARRAY[0..BUFFSIZE] OF Byte; { buffer for Block I/O }
  130.   FileType = FILE;
  131.   FieldRecord = RECORD
  132.                   Name : Str10;
  133.                   Typ : Char;
  134.                   Len : Byte;
  135.                   Dec : Byte;
  136.                   Off : Integer;
  137.                 END;
  138.   FieldArray = ARRAY[1..MAX_FIELDS_IN_RECORD] OF FieldRecord;
  139.   MemoRecord = ARRAY[1..BYTES_IN_MEMO_RECORD] OF Byte;
  140.   MemoFile = FILE OF MemoRecord;
  141.   ChoiceArray = ARRAY[1..MAX_FIELDS_IN_RECORD] OF Integer;
  142.   ByteFile = FILE OF Byte;
  143.  
  144. VAR
  145.   InFile, OutFile : FILE;
  146.   InBuffer, OutBuffer : BufferType;
  147.   Header : HeaderType;
  148.   FieldDesc : FieldType;
  149.   Fields : FieldArray;
  150.   DataRecord : DBFRecord;
  151.   RemainingRecs : Real;
  152.   NextMemo : Real;
  153.   EndFile, FinalWrite : Boolean;
  154.   NumberOfRecs : Real;
  155.   MemoBuffer : MemoRecord;
  156.   InMemo, OutMemo : MemoFile;
  157.   CharChoice : ChoiceArray;
  158.   LogicChoice, MemoChoice : Integer;
  159.   Semicolon : Boolean;
  160.  
  161.   FUNCTION CheckKey : Boolean; { returns True if ^C pressed, False on   }
  162.                                { any other key, pauses screen on ^S     }
  163.   VAR
  164.     Key : Char;
  165.  
  166.   BEGIN
  167.   Read(Kbd, Key);
  168.   CASE Key OF
  169.     ^C : CheckKey := True;
  170.     ^S : BEGIN
  171.          Key := Chr(0);
  172.          WHILE Key <> ^S DO Read(Kbd, Key);
  173.          CheckKey := False;
  174.          END;
  175.   ELSE
  176.   CheckKey := False;
  177.   END;
  178.   END;
  179.  
  180.   PROCEDURE PutB(VAR F : FileType;
  181.                  VAR Buffer : BufferType;
  182.                  B : Byte);
  183.  
  184.   CONST
  185.     Recs : Integer = 25600;
  186.     I : Integer = 0;
  187.  
  188.   BEGIN
  189.   IF FinalWrite THEN
  190.     BEGIN
  191.     Recs := I;
  192.     IF Recs <> 0 THEN BlockWrite(F, Buffer, Recs);
  193.     END
  194.   ELSE
  195.     BEGIN
  196.     Buffer[I] := B;
  197.     I := Succ(I);
  198.     IF I = Recs THEN
  199.       BEGIN
  200.       I := 0;
  201.       BlockWrite(F, Buffer, Recs);
  202.       END;
  203.     END;
  204.   END;
  205.  
  206.   FUNCTION GetB(VAR F : FileType;
  207.                 VAR Buffer : BufferType;
  208.                 VAR B : Byte) : Byte;
  209.  
  210.   CONST
  211.     EndOfReads : Boolean = False;
  212.     Recs : Integer = 25600;
  213.     I : Integer = 25600;
  214.  
  215.   BEGIN
  216.   IF (I = Recs) AND NOT EndOfReads THEN
  217.     BEGIN
  218.     I := 0;
  219.     IF RemainingRecs < Recs THEN Recs := Trunc(RemainingRecs);
  220.     {$I-} BlockRead(F, Buffer, Recs); {$I+}
  221.     IF IOResult <> 0 THEN EndOfReads := True;
  222.     RemainingRecs := RemainingRecs-Recs;
  223.     IF RemainingRecs = 0 THEN EndOfReads := True;
  224.     END;
  225.   B := Buffer[I];
  226.   GetB := B;
  227.   I := Succ(I);
  228.   IF EndOfReads AND (Succ(I) = Recs)
  229.   THEN EndFile := True;
  230.   END;
  231.  
  232.   FUNCTION CopyByte(VAR InFile, OutFile : FileType;
  233.                     VAR InBuffer, OutBuffer : BufferType;
  234.                     VAR B : Byte) : Byte;
  235.  
  236.   BEGIN
  237.   PutB(OutFile, OutBuffer, GetB(InFile, InBuffer, B));
  238.   CopyByte := B;
  239.   END;
  240.  
  241.   PROCEDURE TootYourHorn;
  242.  
  243.   BEGIN
  244.   NoSound;
  245.   Sound(440); Delay(250); NoSound; Delay(20);
  246.   Sound(440); Delay(250); NoSound; Delay(20);
  247.   Sound(440); Delay(250); NoSound; Delay(20);
  248.   Sound(352); Delay(1000); NoSound;
  249.   END;
  250.  
  251.   FUNCTION OpenFile(VAR F : FileType; FileName : Str80) : Integer;
  252.  
  253.   BEGIN
  254.   Assign(F, FileName);
  255.   {$I-} Reset(F,1); {$I+}  {the '1' parameter sets the record size}
  256.   OpenFile := IOResult;
  257.   END;
  258.  
  259.   PROCEDURE CloseFiles;
  260.  
  261.   BEGIN
  262.   PutB(OutFile, OutBuffer, 26);
  263.   FinalWrite := True;
  264.   PutB(OutFile, OutBuffer, 26);
  265.   Close(OutFile);
  266.   Close(InFile);
  267.   Close(OutMemo);
  268.   Close(InMemo);
  269.   Halt;
  270.   END;
  271.  
  272.   PROCEDURE HeaderError;
  273.  
  274.   BEGIN
  275.   WriteLn;
  276.   WriteLn('Database Header has been compromised.');
  277.   WriteLn('I guess you will need someone better than I to fix this file!');
  278.   CloseFiles;
  279.   END;
  280.  
  281.   PROCEDURE Pause;
  282.  
  283.   BEGIN
  284.   WriteLn;
  285.   WriteLn('Press any key to continue . . .(^C to abort)');
  286.   IF CheckKey THEN CloseFiles;
  287.   END;
  288.  
  289.   PROCEDURE DisplayStructure(VAR FieldDesc : FieldType;
  290.                              VAR Field : FieldRecord);
  291.  
  292.   VAR
  293.     I : Integer;
  294.  
  295.   CONST
  296.     Offset : Integer = 1;     {Offset of field within record }
  297.  
  298.   BEGIN
  299.   WITH Field DO
  300.     BEGIN
  301.     I := 0;
  302.     Name := '          ';
  303.     REPEAT
  304.     Name[Succ(I)] := Chr(FieldDesc[I]);
  305.     I := Succ(I);
  306.     UNTIL FieldDesc[I] = 0;
  307.     Typ := Char(FieldDesc[11]);
  308.     Len := FieldDesc[16];
  309.     Dec := FieldDesc[17];
  310.     Off := Offset;
  311.     Offset := Offset+Len;
  312.     Write('. ', Name, '    ', Typ, '      ', Len:3);
  313.     IF Typ = 'N' THEN Write('     ', Dec:2);
  314.     IF NOT(Typ IN ['C', 'N', 'L', 'M', 'D']) THEN HeaderError;
  315.     END;
  316.   END;
  317.  
  318.   PROCEDURE DisplayFields(VAR Fields : FieldArray;
  319.                           FieldCount : Integer;
  320.                           FTyp : Char);
  321.  
  322.   VAR
  323.     I, R, C : Integer;
  324.     S : Str80;
  325.  
  326.   BEGIN
  327.   CASE FTyp OF
  328.     'C' : S := 'Select one or more Character fields to convert to a Memo';
  329.     'L' : S := 'Select a Logical field to indicate Memo presence';
  330.     'M' : S := 'Select the destination Memo field';
  331.   END;
  332.   I := (80-Length(S)) DIV 2;
  333.   Window(1, 1, 80, 25); ClrScr; GoToXY(1, 1);
  334.   TextBackground(Yellow); TextColor(Blue); ClrEol;
  335.   GoToXY(I, 1); Write(S);
  336.   TextBackground(Blue); TextColor(Yellow);
  337.   Window(1, 2, 80, 25); GoToXY(1, 1);
  338.   R := 1; C := 1; I := 1;
  339.   WHILE I <= FieldCount DO
  340.     BEGIN
  341.     WITH Fields[I] DO
  342.       BEGIN
  343.       IF Typ = FTyp THEN
  344.         BEGIN
  345.         GoToXY(C, R);
  346.         Write(I:2, ' ', Name);
  347.         R := Succ(R);
  348.         IF R = 20 THEN C := C+15;
  349.         IF C > 70 THEN BEGIN C := 1; Pause; ClrScr; END;
  350.         END;
  351.       END;
  352.     I := Succ(I);
  353.     END;
  354.   END;
  355.  
  356.   FUNCTION GetField(FieldCount : Integer; S : Str80) : Integer;
  357.  
  358.   CONST
  359.     Valid : ValidChar = ['0'..'9'];
  360.   VAR
  361.     I, Code : Integer;
  362.     Done : Boolean;
  363.     Response : Str80;
  364.  
  365.   BEGIN
  366.   Window(1, 1, 80, 25);
  367.   Done := False;
  368.   WHILE NOT Done DO
  369.     BEGIN
  370.     GoToXY(1, 22); Write(S); I := Length(S)+1;
  371.     Response := GetStrng(Valid, 3, 22, I, False);
  372.     Val(Response, I, Code);
  373.     IF (Code = 0) AND (I IN [0..FieldCount]) THEN
  374.       BEGIN
  375.       GetField := I;
  376.       Done := True;
  377.       END
  378.     ELSE
  379.       BEGIN
  380.       GoToXY(10, 25);
  381.       Write('Must be 0..', FieldCount:3);
  382.       END;
  383.     END;
  384.   END;
  385.  
  386.   PROCEDURE SelectFields(VAR Fields : FieldArray;
  387.                          FieldCount : Integer);
  388.  
  389.   VAR
  390.     I, R, C, Code : Integer;
  391.     Done, FinallyDone : Boolean;
  392.     Response : Str80;
  393.     Ch : Char;
  394.  
  395.   BEGIN
  396.   FinallyDone := False;
  397.   WHILE NOT FinallyDone DO BEGIN
  398.   DisplayFields(Fields, FieldCount, 'C');
  399.   Window(1, 22, 80, 25);
  400.   ClrScr;
  401.   I := 1; C := 1;
  402.   Done := False;
  403.   WHILE NOT Done DO
  404.     BEGIN
  405.     CharChoice[I] := GetField(FieldCount, 'Select Character fields:');
  406.     IF CharChoice[I] = 0 THEN
  407.       Done := True
  408.     ELSE IF Fields[CharChoice[I]].Typ = 'C' THEN
  409.       BEGIN
  410.       GoToXY(C, 24);
  411.       Write(CharChoice[I]:2, ',');
  412.       C := C+3;
  413.       I := Succ(I);
  414.       END;
  415.     END;
  416.   Window(1, 1, 80, 25);
  417.   ClrScr;
  418.   I := 1;
  419.   GoToXY(1, 1);
  420.   WriteLn('The character fields you have chosen are:');
  421.   WHILE CharChoice[I] <> 0 DO
  422.     BEGIN
  423.     WriteLn(CharChoice[I]:2, ' ', Fields[CharChoice[I]].Name);
  424.     I := Succ(I);
  425.     END;
  426.   WriteLn('Are these fields correct? (Y/N)');
  427.   Read(Kbd, Ch);
  428.   IF UpCase(Ch) = 'Y' THEN FinallyDone := True;
  429.   END;
  430.   FinallyDone := False;
  431.   WHILE NOT FinallyDone DO BEGIN
  432.   DisplayFields(Fields, FieldCount, 'L');
  433.   GoToXY(20, 20);
  434.   Write('Choose one Logic field (not mandatory)');
  435.   Window(1, 22, 80, 25);
  436.   ClrScr;
  437.   Done := False;
  438.   WHILE NOT Done DO
  439.     BEGIN
  440.     LogicChoice := GetField(FieldCount, 'Select a Logic field:');
  441.     IF LogicChoice = 0 THEN
  442.       Done := True
  443.     ELSE IF Fields[LogicChoice].Typ = 'L' THEN
  444.       BEGIN
  445.       Done := True;
  446.       END;
  447.     END;
  448.   Window(1, 1, 80, 25);
  449.   ClrScr;
  450.   GoToXY(1, 1);
  451.   IF LogicChoice > 0 THEN
  452.     BEGIN
  453.     WriteLn('The Logic field you have chosen is:');
  454.     WriteLn(LogicChoice:2, ' ', Fields[LogicChoice].Name);
  455.     END
  456.   ELSE
  457.     WriteLn('You have chosen no logic field.');
  458.   WriteLn;
  459.   WriteLn('Is this correct? (Y/N)');
  460.   Read(Kbd, Ch);
  461.   IF UpCase(Ch) = 'Y' THEN FinallyDone := True;
  462.   END;
  463.   FinallyDone := False;
  464.   WHILE NOT FinallyDone DO BEGIN
  465.   DisplayFields(Fields, FieldCount, 'M');
  466.   GoToXY(20, 20);
  467.   Write('Choose one Memo field ');
  468.   Window(1, 22, 80, 25);
  469.   ClrScr;
  470.   Done := False;
  471.   WHILE NOT Done DO
  472.     BEGIN
  473.     MemoChoice := GetField(FieldCount, 'Select a Memo field:');
  474.     IF MemoChoice = 0 THEN
  475.       BEGIN
  476.       GoToXY(40, 23);
  477.       Write('Must choose a Memo field');
  478.       END
  479.     ELSE IF Fields[MemoChoice].Typ = 'M' THEN
  480.       Done := True;
  481.     END;
  482.   Window(1, 1, 80, 25);
  483.   ClrScr;
  484.   GoToXY(1, 1);
  485.   WriteLn('The Memo field you have chosen is:');
  486.   WriteLn(MemoChoice:2, ' ', Fields[MemoChoice].Name);
  487.   WriteLn;
  488.   WriteLn('Is this correct? (Y/N)');
  489.   Read(Kbd, Ch);
  490.   IF UpCase(Ch) = 'Y' THEN FinallyDone := True;
  491.   END;
  492.  
  493.   END;                        {FinallyFinallyDone!}
  494.  
  495.   PROCEDURE DisplayHeader(VAR Header : HeaderType;
  496.                           VAR RecordLength : Integer;
  497.                           VAR HeaderLength : Integer);
  498.  
  499.   BEGIN
  500.   WriteLn;
  501.   WriteLn('Date of last update:  ', Header[2], '/', Header[3], '/', Header[1]);
  502.   NumberOfRecs := (Header[4]*1)+
  503.   (Header[5]*256)+
  504.   (Header[6]*65536.0)+
  505.   (Header[7]*16777216.0);
  506.   WriteLn('Number of Records: ', NumberOfRecs:10:0);
  507.   HeaderLength := Header[8]+(256*Header[9]);
  508.   RecordLength := Header[10]+(256*Header[11]);
  509.   END;
  510.  
  511.   PROCEDURE ReadMemo(VAR M : MemoFile;
  512.                      VAR MemoBuffer : MemoRecord;
  513.                      Ptr : Real);
  514.  
  515.   BEGIN
  516.   LongSeek(M, Ptr);
  517.   Read(M, MemoBuffer);
  518.   END;
  519.  
  520.   PROCEDURE WriteMemo(VAR M : MemoFile;
  521.                       VAR MemoBuffer : MemoRecord;
  522.                       Ptr : Real);
  523.   BEGIN
  524.   LongSeek(M, Ptr);
  525.   Write(M, MemoBuffer);
  526.   FillChar(MemoBuffer, 512, #0);
  527.   END;
  528.  
  529.   FUNCTION GetNextMemoPointer(VAR M : MemoFile) : Real;
  530.  
  531.   VAR
  532.     MBuff : MemoRecord;
  533.  
  534.   BEGIN
  535.   ReadMemo(M, MBuff, 0);
  536.   GetNextMemoPointer := MBuff[1]*1.+
  537.                         MBuff[2]*256.+
  538.                         MBuff[3]*65536.+
  539.                         MBuff[4]*16777216.;
  540.   END;
  541.  
  542.   PROCEDURE PutM(VAR I : Integer; B : Integer);
  543.  
  544.   BEGIN
  545.   MemoBuffer[I] := B;
  546.   I := Succ(I);
  547.   IF (I > 512) OR (B = 26) THEN
  548.     BEGIN
  549.     I := 1;
  550.     WriteMemo(OutMemo, MemoBuffer, NextMemo);
  551.     NextMemo := NextMemo+1;
  552.     END;
  553.   END;
  554.  
  555.   PROCEDURE PutMemo(VAR Memo : Str255);
  556.  
  557.   CONST
  558.     I : Integer = 1;
  559.     C : Integer = 1;
  560.  
  561.   VAR
  562.     J, M : Integer;
  563.  
  564.     PROCEDURE EndOfLine;
  565.  
  566.     BEGIN
  567.     PutM(I, $8D);
  568.     PutM(I, $0A);
  569.     C := 1;
  570.     END;
  571.  
  572.   BEGIN
  573.   M := Length(Memo);
  574.   IF M <> 0 THEN
  575.     BEGIN
  576.     IF Memo = Chr(26) THEN
  577.       BEGIN
  578.       PutM(I, 26);
  579.       C := 1;
  580.       END
  581.     ELSE
  582.       BEGIN
  583.       Memo := Memo+'*';
  584.       J := 1;
  585.       WHILE J <= M DO
  586.         BEGIN
  587.         IF C >= 65 THEN
  588.           IF ((Memo[J] = ' ') AND (Memo[Succ(J)] <> ' '))
  589.           OR (C >= 78) THEN EndOfLine;
  590.         IF (Memo[J] = ';') AND (Semicolon) THEN
  591.           EndOfLine
  592.         ELSE
  593.           BEGIN PutM(I, Ord(Memo[J])); C := Succ(C); END;
  594.         J := Succ(J);
  595.         END;
  596.       END;
  597.     END;
  598.   END;
  599.  
  600.   PROCEDURE PutNextMemoPointer(VAR M : MemoFile; R : Real);
  601.  
  602.   VAR
  603.     MBuff : MemoRecord;
  604.  
  605.   BEGIN
  606.   FillChar(MBuff, 512, #0);
  607.   MBuff[4] := Trunc(R/16777216.0);
  608.   R := R-(MBuff[4]*16777216.0);
  609.   MBuff[3] := Trunc(R/65536.0);
  610.   R := R-(MBuff[3]*65536.0);
  611.   MBuff[2] := Trunc(R/256);
  612.   R := R-(MBuff[2]*256);
  613.   MBuff[1] := Trunc(R);
  614.   WriteMemo(M, MBuff, 0);
  615.   END;
  616.  
  617. VAR
  618.   RecordLength, FieldCount : Integer;
  619.  
  620.   PROCEDURE CopyOneRecord;
  621.  
  622.   VAR
  623.     I, J, M, L : Integer;
  624.     B : Byte;
  625.     Memo : Str255;
  626.     ThisMemo : Real;
  627.     MemoPointer : Str10;
  628.     MemoEntered : Boolean;
  629.  
  630.     PROCEDURE GetARecord;
  631.  
  632.     BEGIN
  633.     I := 0;
  634.     WHILE (I < RecordLength) AND (NOT EndFile) DO
  635.       BEGIN
  636.       DataRecord[I] := GetB(InFile, InBuffer, B);
  637.       I := Succ(I);
  638.       END;
  639.     END;
  640.  
  641.     PROCEDURE PutARecord;
  642.  
  643.     BEGIN
  644.     I := 0;
  645.     WHILE (I < RecordLength) DO
  646.       BEGIN
  647.       B := DataRecord[I];
  648.       PutB(OutFile, OutBuffer, B);
  649.       I := Succ(I);
  650.       END;
  651.     END;
  652.  
  653.   BEGIN
  654.   ThisMemo := NextMemo;
  655.   GetARecord;
  656.   I := 1; MemoEntered := False;
  657.   WHILE CharChoice[I] <> 0 DO
  658.     BEGIN
  659.     WITH Fields[CharChoice[I]] DO
  660.       BEGIN
  661.       L := 1; Memo := ''; M := 0; J := Off;
  662.       WHILE L <= Len DO
  663.         BEGIN
  664.         B := DataRecord[J];
  665.         Memo := Memo+Chr(B);
  666.         IF B <> 32 THEN M := L;
  667.         L := Succ(L); J := Succ(J);
  668.         END;
  669.       IF M > 0 THEN
  670.         BEGIN
  671.         Memo[0] := Chr(M);
  672.         Memo := Memo+' ';
  673.         MemoEntered := True;
  674.         WriteLn(Name, ' ', Memo);
  675.         PutMemo(Memo);
  676.         END;
  677.       END;
  678.     I := Succ(I);
  679.     END;
  680.   IF MemoEntered THEN
  681.     BEGIN
  682.     Memo := Chr(26);
  683.     PutMemo(Memo);
  684.     END;
  685.   IF LogicChoice <> 0 THEN
  686.     BEGIN
  687.     IF MemoEntered THEN
  688.       B := $59 {'Y'}
  689.     ELSE
  690.       B := $4E; {'N'}
  691.     DataRecord[Fields[LogicChoice].Off] := B;
  692.     END;
  693.   IF MemoEntered THEN
  694.     Str(ThisMemo:10:0, MemoPointer)
  695.   ELSE
  696.     Str(0:10, MemoPointer);
  697.   J := Fields[MemoChoice].Off;
  698.   FOR I := 1 TO 10 DO
  699.     BEGIN
  700.     DataRecord[J] := Ord(MemoPointer[I]);
  701.     J := Succ(J);
  702.     END;
  703.   PutARecord;
  704.   END;
  705.  
  706.   PROCEDURE SignOn;
  707.  
  708.   BEGIN
  709.   ClrScr; GoToXY(10, 10);
  710.   WriteLn('CTOM   -- a program to convert Char fields TO');
  711.   GoToXY(20, 11); WriteLn('dBASE III Memo files (.DBT).');
  712.   GoToXY(30, 13); WriteLn('Ver. ', VER);
  713.   GoToXY(28, 15); WriteLn('by J. Troutman');
  714.   GoToXY(20, 17); WriteLn('Ctrl-S Pauses -- Ctrl-C Aborts');
  715.   GoToXY(1, 22); Pause;
  716.   END;
  717.  
  718. VAR
  719.   Found, Break : Boolean;
  720.   HeaderLength, I, ByteCount : Integer;
  721.   Col, Row : Integer;
  722.   B : Byte;
  723.   R, RecordCount : Real;
  724.   InFileName, OutFileName, Response : Str80;
  725.  
  726. CONST
  727.   ValidFileName :
  728.   ValidChar = ['!', '#'..')', '-', '0'..'9', '@'..'Z', '_', '`', '{', '}', '~'];
  729.   YesNo : ValidChar = ['Y', 'N'];
  730.  
  731. BEGIN                         { CharacterTOMemo }
  732. EndFile := False; FinalWrite := False;
  733. Break := False; Found := False; ByteCount := 0;
  734. TextBackground(Blue);
  735. TextColor(Yellow);
  736. SignOn; ClrScr;
  737. GoToXY(1, 5);
  738. Write('Enter Source File Name (.DBF extension assumed): ');
  739. WHILE NOT Found DO
  740.   BEGIN
  741.   InFileName := GetStrng(ValidFileName, 8, 5, 50, True)+'.DBF';
  742.   IF OpenFile(InFile, InFileName) <> 0 THEN
  743.     BEGIN
  744.     GoToXY(1, 7);
  745.     WriteLn('I cannot seem to find ', InFileName, '.');
  746.     WriteLn('Could you run it by me again?');
  747.     Pause; Window(1, 6, 80, 25); ClrScr; Window(1, 1, 80, 25);
  748.     END
  749.   ELSE Found := True;
  750.   END;
  751. RemainingRecs := LongFileSize(InFile);
  752. GoToXY(1, 7);
  753. WriteLn('There are ', RemainingRecs:7:0, ' bytes in ', InFileName, '.');
  754. Found := False;
  755. GoToXY(1, 10);
  756. Write('Enter Destination File Name (.DBF assumed): ');
  757. WHILE NOT Found DO
  758.   BEGIN
  759.   OutFileName := GetStrng(ValidFileName, 8, 10, 45, True)+'.DBF';
  760.   GoToXY(1, 12);
  761.   IF InFileName = OutFileName THEN
  762.     Write('Sorry, but both files may not have the same name.')
  763.   ELSE
  764.     Found := True;
  765.   END;
  766. Assign(OutFile, OutFileName);
  767. Rewrite(OutFile,1);
  768. I := Length(InFileName);
  769. InFileName[I] := 'T';
  770. Assign(InMemo, InFileName);
  771. {$I-} Reset(InMemo);          {$I-}
  772. IF IOResult <> 0 THEN BEGIN WriteLn('Cannot find memo file'); Halt; END;
  773. I := Length(OutFileName);
  774. OutFileName[I] := 'T';
  775. Assign(OutMemo, OutFileName);
  776. Rewrite(OutMemo);
  777. WriteLn(Output, 'Reading Header Data');
  778. I := 0;
  779. WHILE I < 32 DO BEGIN
  780. Header[I] := CopyByte(InFile, OutFile, InBuffer, OutBuffer, B);
  781. I := Succ(I);
  782. ByteCount := Succ(ByteCount);
  783. END;
  784. WriteLn;
  785. DisplayHeader(Header, RecordLength, HeaderLength);
  786. Pause;
  787. FieldCount := 0; Row := 1; Col := 1; ClrScr; GoToXY(Col, Row);
  788. Write(' #  Field Name   Type  Length  Decimal');
  789. Col := 41; GoToXY(Col, Row);
  790. Write(' #  Field Name   Type  Length  Decimal');
  791. Window(1, 2, 80, 25); Col := 1; ClrScr;
  792. WHILE GetB(InFile, InBuffer, B) <> $0D DO
  793.   BEGIN
  794.   ByteCount := Succ(ByteCount);
  795.   IF ByteCount > HeaderLength THEN HeaderError;
  796.   I := 0;
  797.   FieldDesc[I] := B;
  798.   PutB(OutFile, OutBuffer, FieldDesc[I]);
  799.   REPEAT
  800.     I := Succ(I);
  801.     FieldDesc[I] := CopyByte(InFile, OutFile, InBuffer, OutBuffer, B);
  802.     ByteCount := Succ(ByteCount);
  803.   UNTIL I = 31;
  804.   FieldCount := Succ(FieldCount);
  805.   GoToXY(Col, Row); Write(FieldCount:2);
  806.   DisplayStructure(FieldDesc, Fields[FieldCount]);
  807.   Row := FieldCount MOD 22+1;
  808.   IF Row = 1 THEN
  809.     IF Col = 41 THEN
  810.       BEGIN
  811.       Col := 1;
  812.       GoToXY(1, 22);
  813.       Pause;
  814.       ClrScr;
  815.       END
  816.     ELSE
  817.       Col := 41;
  818.   IF KeyPressed THEN IF CheckKey THEN CloseFiles;
  819.   END; {WHILE GetB(InFile, InBuffer, B) <> $0D}
  820. PutB(OutFile, OutBuffer, B);  { the $0D byte }
  821. GoToXY(1, 22);
  822. ByteCount := Succ(ByteCount);
  823. Write('          Total Length: ', RecordLength:4);
  824.  
  825. {The original dBASE III files inserted a NUL character after the $0D at the
  826.  end of the header before the data began; Plus does not have this NUL
  827.  character.  The following IF statement tests for the presence of the NUL.}
  828.  
  829. IF InBuffer[Succ(ByteCount)] = 0 THEN
  830.   BEGIN
  831.   B := CopyByte(InFile, OutFile, InBuffer, OutBuffer, B);
  832.   ByteCount := Succ(ByteCount);
  833.   END;
  834. GoToXY(41, 22);
  835. Write('HeaderLength  = ', HeaderLength);
  836.  
  837. { After a dBASE file has been dConverted from II to III, there is frequently
  838.   some muck left in the header until the file has been USEd in dBASE.  The
  839.   following IF statement checks for the muck. }
  840.  
  841. IF HeaderLength > ByteCount THEN
  842.   WHILE ByteCount < HeaderLength DO
  843.     BEGIN
  844.     B := CopyByte(InFile, OutFile, InBuffer, OutBuffer, B);
  845.     ByteCount := Succ(ByteCount);
  846.     END;
  847.  
  848. Pause;
  849. SelectFields(Fields, FieldCount);
  850. Window(1, 1, 80, 25); ClrScr; GoToXY(1, 10);
  851. Write('Do you want semicolons converted to soft carriage returns?');
  852. Response := GetStrng(YesNo, 1, 10, 60, True);
  853. IF Response = 'Y' THEN Semicolon := True ELSE Semicolon := False;
  854. NextMemo := GetNextMemoPointer(InMemo);
  855. R := 0;
  856. WHILE R < NextMemo DO
  857.   BEGIN
  858.   ReadMemo(InMemo, MemoBuffer, R);
  859.   WriteMemo(OutMemo, MemoBuffer, R);
  860.   R := R+1;
  861.   END;
  862. RecordCount := 0; Window(1, 1, 80, 25); ClrScr; GoToXY(1, 25);
  863. TextBackground(Yellow); TextColor(Blue); ClrEol;
  864. GoToXY(15, 25); Write('Ctrl-S to Pause     Ctrl-Break or Ctrl-C to abort');
  865. TextBackground(Blue); TextColor(Yellow);
  866. Window(1, 1, 80, 4); GoToXY(1, 2);
  867. Write('Record Number:         1 of ', NumberOfRecs:10:0);
  868. Write('  Next Memo Pointer:', NextMemo:10:0);
  869. WHILE (NOT EndFile) AND (NOT Break) AND (RecordCount < NumberOfRecs) DO
  870.   BEGIN
  871.   RecordCount := RecordCount+1;
  872.   Window(1, 1, 80, 4);
  873.   GoToXY(15, 2); Write(RecordCount:10:0);
  874.   GoToXY(60, 2); Write(NextMemo:10:0);
  875.   Window(1, 5, 80, 24); ClrScr; GoToXY(1, 1);
  876.   CopyOneRecord;
  877.   PutNextMemoPointer(OutMemo, NextMemo);
  878.   IF KeyPressed THEN Break := CheckKey;
  879.   END;
  880. TootYourHorn;
  881. CloseFiles;
  882. END.
  883.